﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Maknys.Consultator.DomainModel
{
    public class TreeNode<T>
    {
        private TreeNode<T> parent;
        private TreeNodeList<T> children;
        private T Vvalue;

        public TreeNode<T> Parent
        {
            get { return parent; }
            set
            {
                if (value == parent)
                    return;

                if (parent != null)
                    parent.Children.Remove(this);

                if (value != null && !value.Children.Contains(this))
                    value.Children.Add(this);

                parent = value;
            }
        }

        public TreeNodeList<T> Children
        {
            get { return children; }
            private set { children = value; }
        }
 
        public T Value
        {
            get { return Vvalue; }
            set { Vvalue = value; }
        }

        public TreeNode()
        {
            Parent = null;
            Children = new TreeNodeList<T>(this);
        }

        public TreeNode(TreeNode<T> Parent)
        {
            this.Parent = Parent;
            Children = new TreeNodeList<T>(this);
        }

        public IEnumerable<TreeNode<T>> GetEnumerable(TreeTraversalType TraversalType, TreeTraversalDirection TraversalDirection)
        {
            return GetBreadthFirstEnumerable(TraversalDirection);
        }

        private IEnumerable<TreeNode<T>> GetBreadthFirstEnumerable(TreeTraversalDirection TraversalDirection)
        {
            var queue = new Queue<TreeNode<T>>();
            queue.Enqueue(this);

            while (0 < queue.Count)
            {
                TreeNode<T> node = queue.Dequeue();

                TreeNodeList<T> searchNode = node.Children;

                foreach (TreeNode<T> child in searchNode)
                {
                    queue.Enqueue(child);
                }

                yield return node;
            }
        }

    }
}
